package com.zoe.app.aspect;

import cn.hutool.json.JSONUtil;
import com.zoe.app.annotation.ParamAnalysis;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

/**
 * @author zbg
 * @date 2023/07/05
 * @description
 */
@Aspect
@Slf4j
@Component
public class ParamAspect {

    private final ExpressionParser parser = new SpelExpressionParser();

    private final ParserContext templateParserContext = new TemplateParserContext();

    private final StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();

    @Around(value = "@annotation(paramAnalysis)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint proceedingJoinPoint, ParamAnalysis paramAnalysis) {
        String spel = paramAnalysis.value();
        Object[] args = proceedingJoinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Class returnType = methodSignature.getReturnType();
        String[] parameterNames = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < parameterNames.length; i++) {
            String parameterName = parameterNames[i];
            Object arg = args[i];
            standardEvaluationContext.setVariable(parameterName, arg);
        }
        Object value = parser.parseExpression(spel, templateParserContext).getValue(standardEvaluationContext, paramAnalysis.returnType());
        log.info("参数解析 ==> {}", JSONUtil.toJsonStr(value));
        Object proceed = proceedingJoinPoint.proceed();
        return proceed;
    }
}
